module apb_slave
(
    //------------------------APB Interface------------------------------
    //Outputs
    output reg [31:0] PRDATA,                         // APB read data
    output            PREADY,                         // APB ready signal
    output            PSLVERR,                        // APB error response
    //INPUTS
    input         PCLK,                               // APB Bus Clock
    input         PRESETn,                            // APB Reset
    input  [31:0] PADDR,                              // APB address
    input         PSEL,                               // APB select line
    input         PENABLE,                            // APB trans
    input         PWRITE,                             // APB Write
    input  [31:0] PWDATA,                             // APB write data
    
    //---------------------- Hit & miss flags ---------------------------
    input       hit,
    input       miss,

    //---------------------- L2 Cache registers -------------------------
    output reg [31:0]  reg_conf0,
    output reg [31:0]  reg_conf1,
    output reg [31:0]  cnt_miss,
    output reg [31:0]  cnt_hit
);


// Declaration of internal constants for FSM
`define IDLE    2'b00
`define ACCESS  2'b10


// Should be defined in a constant file
`define L2CACHE_CONF_REG0_ADDR 2'b00
`define L2CACHE_CONF_REG1_ADDR 2'b01
`define L2CACHE_HIT_CNT_ADDR   2'b10
`define L2CACHE_MISS_CNT_ADDR  2'b11

reg         state;

assign PRESETn = 1'b1;  // apb register interface is always ready
assign PSLVERR = 1'b0;  // apb register interface response is always okay



always @(posedge PCLK or negedge PRESETn) begin
    if (!PRESETn) begin
        state       = `IDLE ;
        reg_conf0   = {32{1'b0}};
        reg_conf1   = {32{1'b0}};
        cnt_miss    = {32{1'b0}};
        cnt_hit     = {32{1'b0}};


    end else begin
        case (state)
            `IDLE : begin
                if (PSEL == 1'b1) begin
                    state       = `ACCESS;

                    if (PWRITE == 1'b1) begin
                        case (PADDR)
                            `L2CACHE_CONF_REG0_ADDR : reg_conf0 = PWDATA;
                            `L2CACHE_CONF_REG1_ADDR : reg_conf1 = PWDATA;
                            `L2CACHE_HIT_CNT_ADDR   : cnt_hit   = PWDATA;
                            `L2CACHE_MISS_CNT_ADDR  : cnt_miss  = PWDATA;
                        endcase

                    end else begin
                        case (PADDR)
                            `L2CACHE_CONF_REG0_ADDR : PRDATA    = reg_conf0;
                            `L2CACHE_CONF_REG1_ADDR : PRDATA    = reg_conf1;
                            `L2CACHE_HIT_CNT_ADDR   : PRDATA    = cnt_hit;
                            `L2CACHE_MISS_CNT_ADDR  : PRDATA    = cnt_miss;
                        endcase
                    end
                end

                // Hit or miss signal triggers respective counter
                else begin 
                    case ({hit,miss})
                        2'b01   : cnt_miss = cnt_miss+1;
                        2'b10   : cnt_hit  = cnt_hit+1;
                    endcase
                end
            end

            `ACCESS : begin
                state   = `IDLE;
            end
        endcase
    end
end
// Clear Verilog Defines

//   FSM States (2-state FSM)
`undef IDLE
`undef ACCESS
endmodule
